
`include "common_header.verilog"

//  *************************************************************************
//  File : mld_read_sm_40g_64b.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : MLD Read SM - reading from the deskew buffer under MLD control
//  Version     : $Id: mld_read_sm_40g_64b.v,v 1.2 2014/10/09 14:58:07 dk Exp $
//  *************************************************************************

module mld_read_sm_40g_64b (

        reset_rxclk,
        cgmii_rxclk,
        vl_intvl,
        disable_mld,

`ifdef MTIPPCS82_EEE_ENA 

        ram_period,
        desk_read_extra,
        read_adjust_req,

`endif

        mld_rst,
        buf_aempty,
        buf_empty,
        desk_buf_rd,
        desk_buf_rd_vec,
        desk_buf_data_val,
        desk_buf_data_val_r,
        desk_buf_data_val_vec,
        desk_buf_data_val_vec_r,
        desk_buf_data_mld_adv,
        desk_buf_data_mld_dval,
        desk_buf_marker_dval
                        );

input           reset_rxclk;            //  async active high reset
input           cgmii_rxclk;            //  ref clock
input   [15:0]  vl_intvl;               //  test mode to speed up simulation        
input           disable_mld;            //  disable MLD (10G/25G mode setting)
`ifdef MTIPPCS82_EEE_ENA 
input           ram_period;             // if 1 - short RAM mode is set 
input  [3:0]    desk_read_extra;        // one bit per lane, if set corresponding buffer should not be read for one period of RAM
input           read_adjust_req;        // one clock pulse - if set, the markers should be adjussted as reflected in desk_read_extra
`endif
input           mld_rst;                //  software reset
input   [3:0]   buf_aempty;             //  deskew buffer status almost empty
input   [3:0]   buf_empty;              //  deskew buffer status empty
output          desk_buf_rd;            //  read from the Deskew Buffer
output          desk_buf_data_val;      //  data valid from the Deskew Buffer
output          desk_buf_data_val_r;    //  data valid from the Register 
output  [3:0]   desk_buf_rd_vec;        //  read from the Deskew Buffers (one bit per Buffer) 
output  [3:0]   desk_buf_data_val_vec;  //  data valid from the Deskew Buffer
output  [3:0]   desk_buf_data_val_vec_r;//  data valid from the Register 

output          desk_buf_data_mld_adv;  //  data valid without markers, advance (1 delayed, after memory output register)
output          desk_buf_data_mld_dval; //  data valid from the Register without marker
output          desk_buf_marker_dval;   //  current block is a marker


wire            desk_buf_data_mld_adv;
wire            desk_buf_data_mld_dval; 
wire            desk_buf_marker_dval; 

wire            desk_buf_marker_dval_nxt;    //  next column will be a marker
reg             desk_buf_rd;            //  read from the Deskew Buffers
reg             desk_buf_data_val;      //  write enable to the register
reg             desk_buf_data_val_r;    //  read from the register

reg     [3:0]   desk_buf_rd_vec;        //  read from the Deskew Buffers (one bit per Buffer) 
reg     [3:0]   desk_buf_data_val_vec;  //  data valid from the Deskew Buffer
reg     [3:0]   desk_buf_data_val_vec_r;//  data valid from the Register 
reg     [1:0]   read_cycle_cnt;

wire            mld_rst_disable;            //  software reset


`ifdef MTIPPCS82_EEE_ENA 
reg             read_adjust_req_long;
reg             ram_adjusted_period;
wire            desk_buf_am_rd;
`endif

assign mld_rst_disable = mld_rst | disable_mld;



mld_read_sm_40g_int_64b U_SM40GINT (

        .reset_rxclk                    (reset_rxclk),
        .cgmii_rxclk                    (cgmii_rxclk),
        .vl_intvl                       (vl_intvl),
`ifdef MTIPPCS82_EEE_ENA 
        .ram_period                     (ram_period),
        .read_adjust_req_long           (read_adjust_req_long),
        .desk_buf_am_rd                 (desk_buf_am_rd),
`endif
        .mld_rst                        (mld_rst_disable),
        .desk_buf_rd                    (desk_buf_rd),
        .desk_buf_marker_dval_nxt       (desk_buf_marker_dval_nxt),
        .desk_buf_data_mld_adv          (desk_buf_data_mld_adv),
        .desk_buf_data_mld_dval         (desk_buf_data_mld_dval),
        .desk_buf_marker_dval           (desk_buf_marker_dval)
                );





always @(posedge cgmii_rxclk or posedge reset_rxclk)
begin
        if (reset_rxclk == 1'b 1)
        begin
                read_cycle_cnt <= 2'd 0;	
        end
        else
        begin
                if ( mld_rst_disable == 1'b 1 )
                begin
                        read_cycle_cnt <= 2'd 0;
                end
                else if ( (read_cycle_cnt == 2'd 0 && buf_empty == 4'b 0000) || read_cycle_cnt != 2'd0)
                begin
                        read_cycle_cnt <= read_cycle_cnt + 2'd 1;
                end

      end
end


always @(posedge cgmii_rxclk or posedge reset_rxclk)
begin : process_1
        if (reset_rxclk == 1'b 1)
        begin
                desk_buf_rd <= 1'b 0;
                desk_buf_rd_vec <= 4'b 0;	
        end
        else
        begin
                if (mld_rst == 1'b 1)
                begin
                        desk_buf_rd <= 1'b 0;
                        desk_buf_rd_vec <= 4'b 0;	
                end
                else if (disable_mld == 1'b 1)
                begin
                        // In MLD bypass mode only use Lane0 FIFO. 
                        // Read only every 2nd clock, or with burst when not almost empty.

                        if( (desk_buf_rd==1'b 0 && buf_empty[0]==1'b 0) || buf_aempty[0]==1'b 0 )
                        begin
                                desk_buf_rd <= 1'b 1;
                                desk_buf_rd_vec <= 4'b 0001;	
                        end
                        else
                        begin
                                desk_buf_rd <= 1'b 0;
                                desk_buf_rd_vec <= 4'b 0;	
                        end                
                end
                else if (read_cycle_cnt == 2'd0 && buf_empty == 4'b 0000)
                begin
                        desk_buf_rd <= 1'b 1;
                        `ifdef MTIPPCS82_EEE_ENA
                        if (read_adjust_req_long == 1'b 1 && desk_buf_am_rd == 1'b1 || (desk_buf_am_rd == 1'b0 && ram_adjusted_period == 1'b1))
                        begin
                                desk_buf_rd_vec <= desk_read_extra;
                        end
                        else
                        `endif
                        begin
                                desk_buf_rd_vec <= 4'b 1111;       
                        end               
                end
                else
                begin
                        desk_buf_rd <= 1'b 0;
                        desk_buf_rd_vec <= 4'b 0;	
                end
        end
end



always @(posedge cgmii_rxclk or posedge reset_rxclk)
begin : process_2
        if (reset_rxclk == 1'b 1)
        begin
                desk_buf_data_val       <= 1'b 0;	
                desk_buf_data_val_r     <= 1'b 0;	
                desk_buf_data_val_vec   <= 4'b 0;	
                desk_buf_data_val_vec_r <= 4'b 0;
        end
        else
        begin
                if (mld_rst == 1'b 1)
                begin
                        desk_buf_data_val       <= 1'b 0;	
                        desk_buf_data_val_r     <= 1'b 0;	
                        desk_buf_data_val_vec   <= 4'b 0;	
                        desk_buf_data_val_vec_r <= 4'b 0;

                end
                else
                begin
                        desk_buf_data_val       <= desk_buf_rd;	
                        desk_buf_data_val_r     <= desk_buf_data_val;	
                        desk_buf_data_val_vec   <= desk_buf_rd_vec;	
                        desk_buf_data_val_vec_r <= desk_buf_data_val_vec;

                end
        end
end



`ifdef MTIPPCS82_EEE_ENA 

// The logic below sets adjusted period of the RAM(ram_adjusted_period)
// during this period only required buffers are read.
// Note: the actual ajusted read (desk_buf_rd_vec <= desk_read_extra) starts
// one read pulse earlier than ram_adjusted_period is asserted and
// and also finished  one pulse earlier
// This done to have ajust read aligned with RAM start.


always @(posedge cgmii_rxclk or posedge reset_rxclk)
begin
        if (reset_rxclk == 1'b 1)
        begin
                ram_adjusted_period  <= 1'b0;       
                read_adjust_req_long <= 1'b0;	
        end
        else
        begin
                if (mld_rst_disable == 1'b 1)
                begin
                        ram_adjusted_period  <= 1'b0;
                        read_adjust_req_long <= 1'b0;	
                end
                else if (read_adjust_req == 1'b1)
                begin
                        read_adjust_req_long <= 1'b1;		
                end 
                else if (desk_buf_am_rd == 1'b1 && read_adjust_req_long == 1'b1)
                begin
                        ram_adjusted_period  <= 1'b1;
                        read_adjust_req_long <= 1'b0;        
                end
                else if (desk_buf_am_rd == 1'b1)
                begin
                        ram_adjusted_period <= 1'b0;       
                end                
        end        
end
`endif


endmodule // module mld_read_sm_40g_64b